#include "NeoScrollBarStyle.h"
#include <QPainter>
#include <QStyleOption>

NeoScrollBarStyle::NeoScrollBarStyle(QStyle *style)
    : QProxyStyle(style) {}

NeoScrollBarStyle::NeoScrollBarStyle(const QString &key)
    : QProxyStyle(key) {}

NeoScrollBarStyle::~NeoScrollBarStyle() = default;

void NeoScrollBarStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
    switch (control)
    {
    case CC_ScrollBar:
    {
        if (const QStyleOptionSlider *scrollBarOption = qstyleoption_cast<const QStyleOptionSlider *>(option))
        {
            const int borderRadius = 2;

            painter->save();
            painter->setRenderHint(QPainter::Antialiasing);
            painter->setPen(Qt::NoPen);
            painter->setBrush(Qt::NoBrush);
            QRect sliderRect = subControlRect(control, option, SC_ScrollBarSlider, widget);
            painter->setBrush(Qt::lightGray);
            painter->drawRoundedRect(sliderRect, borderRadius, borderRadius);
            painter->restore();
            return;
        }
        break;
    }
    }
    return QProxyStyle::drawComplexControl(control, option, painter, widget);
}

QRect NeoScrollBarStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const
{
    switch (subControl)
    {
    case SC_ScrollBarAddLine:
    case SC_ScrollBarSubLine:
    {
        return QRect();
    }
    case SC_ScrollBarAddPage:
    {
        if (const QStyleOptionSlider *scrollBarOption = qstyleoption_cast<const QStyleOptionSlider *>(option))
        {
            QRect addLineRect = QProxyStyle::subControlRect(control, option, SC_ScrollBarAddLine, widget);
            QRect addPageRect = QProxyStyle::subControlRect(control, option, SC_ScrollBarAddPage, widget);
            if (scrollBarOption->orientation == Qt::Horizontal)
            {
                addPageRect.setLeft(addLineRect.left());
            }
            else if (scrollBarOption->orientation == Qt::Vertical)
            {
                addPageRect.setTop(addLineRect.top());
            }
            return addPageRect;
        }
        break;
    }
    case SC_ScrollBarSubPage:
    {
        if (const QStyleOptionSlider *scrollBarOption = qstyleoption_cast<const QStyleOptionSlider *>(option))
        {
            QRect subLineRect = QProxyStyle::subControlRect(control, option, SC_ScrollBarSubLine, widget);
            QRect subPageRect = QProxyStyle::subControlRect(control, option, SC_ScrollBarSubPage, widget);
            if (scrollBarOption->orientation == Qt::Horizontal)
            {
                subPageRect.setRight(subLineRect.right());
            }
            else if (scrollBarOption->orientation == Qt::Vertical)
            {
                subPageRect.setBottom(subLineRect.bottom());
            }
            return subPageRect;
        }
        break;
    }
    case SC_ScrollBarSlider:
    {
        if (const QStyleOptionSlider *scrollBarOption = qstyleoption_cast<const QStyleOptionSlider *>(option))
        {
            if (scrollBarOption->orientation == Qt::Horizontal)
            {
                double minWidth = QProxyStyle::pixelMetric(PM_ScrollBarSliderMin, option, widget);
                double width = qMax(1.0 * scrollBarOption->pageStep / (scrollBarOption->maximum - scrollBarOption->minimum + 1) * scrollBarOption->rect.width(), minWidth);
                double x = 1.0 * scrollBarOption->sliderPosition * (scrollBarOption->rect.width() - width) / (scrollBarOption->maximum - scrollBarOption->minimum + 1);
                return QRect(scrollBarOption->rect.x() + x, scrollBarOption->rect.y(),
                             width, scrollBarOption->rect.height());
            }
            else if (scrollBarOption->orientation == Qt::Vertical)
            {
                double minHeight = QProxyStyle::pixelMetric(PM_ScrollBarSliderMin, option, widget);
                double height = qMax(1.0 * scrollBarOption->pageStep / (scrollBarOption->maximum - scrollBarOption->minimum + 1) * scrollBarOption->rect.height(), minHeight);
                double y = 1.0 * scrollBarOption->sliderPosition * (scrollBarOption->rect.height() - height) / (scrollBarOption->maximum - scrollBarOption->minimum + 1);
                return QRect(scrollBarOption->rect.x(), scrollBarOption->rect.y() + y,
                             scrollBarOption->rect.width(), height);
            }
        }
        break;
    }
    default:
        break;
    }
    return QProxyStyle::subControlRect(control, option, subControl, widget);
}

QStyle::SubControl NeoScrollBarStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget) const
{
    if (subControlRect(control, option, SC_ScrollBarAddLine, widget).contains(pos))
    {
        return SC_ScrollBarAddLine;
    }
    else if (subControlRect(control, option, SC_ScrollBarSubLine, widget).contains(pos))
    {
        return SC_ScrollBarSubLine;
    }
    else if (subControlRect(control, option, SC_ScrollBarAddPage, widget).contains(pos))
    {
        return SC_ScrollBarAddPage;
    }
    else if (subControlRect(control, option, SC_ScrollBarSubPage, widget).contains(pos))
    {
        return SC_ScrollBarSubPage;
    }
    else if (subControlRect(control, option, SC_ScrollBarSlider, widget).contains(pos))
    {
        return SC_ScrollBarSlider;
    }
    return QProxyStyle::hitTestComplexControl(control, option, pos, widget);
}

int NeoScrollBarStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
    switch (metric)
    {
    case PM_ScrollBarExtent:
        return 0;
    default:
        break;
    }
    return QProxyStyle::pixelMetric(metric, option, widget);
}